#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;

//02 String写时复制

class CowString{
public:
    CowString()
        :_pstr(new char[5]() + 4){
            ++*(int *)(_pstr-4);
        }

    CowString(const char * pstr)
        :_pstr(new char[strlen(pstr)+5]() + 4){
            strcpy(_pstr,pstr);
            ++*(int *)(_pstr-4);
        }

    CowString(const CowString & rhs)
        :_pstr(rhs._pstr){
            ++*(int *)(_pstr-4);
        }

    //s1=s2;
    CowString & operator=(const CowString & rhs){
        if(this != &rhs){
            if(--*(int *)(_pstr-4) == 0){
                delete [] (_pstr-4);
            }
            _pstr = rhs._pstr;
            ++*(int *)(_pstr-4);
        }
        return *this;
    }

    size_t RefCount() const {
        return *(int *)(_pstr -4);
    }

    size_t size() const{
        return strlen(_pstr);
    } 

    const char * c_str() const {
        return _pstr;
    }

    ~CowString(){
        if(--*(int *)(_pstr-4)==0){
            delete [] (_pstr-4);
        }
    }
private:
    class CharProxy{
    public:
        CharProxy(CowString & self,size_t index)
            :_self(self)
             ,_index(index){

             }

        //写s[0]='H';
        char & operator=(const char & ch){
            if(_index >= _self.size()){
                static char nullchar = '\0';
                cerr << "index error" << endl;
                return nullchar;
            }
            if(_self.RefCount() > 1){
                //01申请新的堆空间
                char * temp = new char[strlen(_self._pstr)+5]() + 4;
                //02深拷贝
                strcpy(temp,_self._pstr);
                //03原有--count
                --*(int *)(_self._pstr-4);
                //04修改指向
                _self._pstr = temp;
                //05新的引用计数=1
                *(int *)(_self._pstr-4)=1;
            }
            _self._pstr[_index] = ch;
            return _self._pstr[_index];
        }

        //读
        friend ostream & operator<<(ostream & os,const CharProxy & s);

    private:
        CowString & _self;
        size_t _index;
    };
public:
    CharProxy  operator[](size_t index) {
        if(index >= size()){
            static CowString s;
            return CharProxy(s,0);
        }
        return CharProxy(*this,index);
    }

    const char & operator[](size_t index) const{
        if(index >= size()){
            static char nullchar = '\0';
            return nullchar;
        }
        return _pstr[index];
    }

    friend ostream & operator<<(ostream & os,const CharProxy & s);

    friend ostream & operator<<(ostream & os,const CowString & s);

    //friend istream & operator>>(istream & is,CowString & s);
private:
    char * _pstr;
};

ostream & operator<<(ostream & os,const CowString::CharProxy & s){
    cout << s._self._pstr[s._index];
    return os;
}

ostream & operator<<(ostream & os,const CowString & s){
    cout << s._pstr;
    return os;
}

//istream & operator>>(istream & is,CowString & s){
//    if(s.RefCount() > 1){
//        --*(int *)(s._pstr - 4);
//    }else{
//        delete [] s._pstr - 4;
//    }
//
//    char ch;
//    vector<char> vec;
//    if((ch = is.get()) != '\n'){
//        vec.push_back(ch);
//    }
//    s._pstr = new char[vec.size()+1]();
//    for(int i = 0; i < vec.size(); ++i){
//        s.(_pstr-4)[i] = vec[i];
//    }
//    return is;
//}

void test(){
    CowString s1("hello");
    cout << s1.size() << endl;
    cout << s1 << endl;
    cout << s1.RefCount() << endl;
    CowString s2(s1);
    cout << s2 << endl;
    cout << s1.RefCount() << endl;
    cout << s2.RefCount() << endl;

    CowString s3("world");
    cout << s3.size() << endl;
    cout << s3 << endl;
    cout << s3.RefCount() << endl;
      
    s3 = s1;
    cout << s3 << endl;
    cout << s3.RefCount() << endl;
    cout << s1.RefCount() << endl;

    const char * pstr = s3.c_str();
    cout << pstr << endl;
    cout << s3.RefCount() << endl;
    cout << s1.RefCount() << endl;

}

void test2(){
    CowString s1("hello");
    cout << s1 << endl;
    cout << s1.RefCount() << endl;
    cout << s1[0] << endl;
    cout << s1.RefCount() << endl;

    cout << "-------------------" << endl;

    CowString s2(s1);
    cout << s2 << endl;
    cout << s1.RefCount() << endl;
    cout << s2.RefCount() << endl;

    s1[0] = 'H';
    cout << s1 << endl;
    cout << s1.RefCount() << endl;
    cout << s2 << endl;
    cout << s2.RefCount() << endl;
}

void test3(){
    const CowString s("hello");
    cout << s << endl;
    cout << s.RefCount() << endl;
    cout << s[0] << endl;
    cout << s.RefCount() << endl;
}

int main()
{
    test3();
    return 0;
}

